﻿
// ChildView.cpp: CChildView 类的实现
//
#include "stdio.h"
#include "pch.h"
#include "framework.h"
#include "resource.h"
#include "ChildView.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define THUNDERUK_POS 10 // 雷在图片中的位置

int nposx[] = { 0,  1,  0, -1};	//12点方向开始，顺时针旋转
int nposy[] = { -1, 0,  1,  0};

// 记录图片位置和值对应关系
// 值 -> 图片位置
int v_p[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};

UINT_PTR timeId = -1;
int curTime = 0;

// CChildView

CChildView::CChildView()
{

	m_bmCells.LoadBitmap(IDB_CELLS);
	m_bmFaces.LoadBitmap(IDB_FACES);
	m_bmNumber.LoadBitmap(IDB_NUM);

	//if (m_bmCells.LoadBitmap(IDB_CELLS))
	//{
	//	BITMAP bm;
	//	m_bmCells.GetObject(sizeof(bm), (LPVOID)&bm);
	//}
	//else
	//	TRACE("载入位图失败\n");
}

CChildView::~CChildView()
{
}


BEGIN_MESSAGE_MAP(CChildView, CWnd)
	ON_WM_PAINT()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDOWN()
	ON_COMMAND(ID_SHOW_ALL_SQUARE, &CChildView::OnShowAllQuare)
	ON_WM_TIMER()
	ON_COMMAND(ID_RESTART, &CChildView::OnRestart)
END_MESSAGE_MAP()



// CChildView 消息处理程序

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.dwExStyle |= WS_EX_CLIENTEDGE;
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(nullptr, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), nullptr);

	return TRUE;
}
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	init(30, 16, 99);
	return 0;
}

// 初始化地图
void CChildView::init(int w, int h, int tnum) {
	EnableWindow(true);

	srand(GetTickCount());
	W = w;
	H = h;
	THUNDERUK_NUM = tnum;

	memset(values, NONE, sizeof values);
	memset(status, OFF, sizeof status);

	// 随机放地雷
	for (int k = 0; k < tnum;) {
		int row = rand() % h;
		int col = rand() % w;
		if (values[row][col]) continue;
		// 放地雷
		values[row][col] = 9;
		k++;
	}
	int r = 0;
	// 计算每个格子的数字
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			if (values[i][j] == 9) continue;
			for (int newX = -1; newX < 2; newX++) {
				for (int newY = -1; newY < 2; newY++) {
					int nextrow = i + newY;
					int nextcol = j + newX;
					if (InBound(nextrow, nextcol) && (9 == values[nextrow][nextcol]))
						values[i][j]++;
				}
			}
		}
	}
	timeId = SetTimer(1, 1000, NULL);
	curTime = 0;

	Invalidate();
}

bool CChildView::InBound(int r, int c) {
	return r >= 0 && r < H && c >= 0 && c < W;
}

void CChildView::OnPaint() {
	CPaintDC dc(this); // device context for painting
	// TODO: 在此处添加消息处理程序代码
	// 不为绘图消息调用 CWnd::OnPaint()
	CDC dcMem;

	// 1.创建一个背景画布，先在该画布上描绘
	dcMem.CreateCompatibleDC(&dc);
	CRect rc;
	GetClientRect(&rc);

	alt.HEIGHTOFF = (rc.Height() - alt.TOP_SHOW_H) / H ;
	alt.WIDTHOFF = rc.Width() / W;

	// 以客户区大小创建画布
	CBitmap bm;
	bm.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
	CBitmap* pbmOld = (CBitmap*)(dcMem.SelectObject(&bm));

	// 2.在画布上描绘
	// 绘制显示栏
	ShowBoard(&dcMem);
	// 绘制网格
	ShowCells(&dcMem);	//在画布上绘制

	// 3.把画布绘制到窗口中
	dc.BitBlt(0, 0, rc.Width(), rc.Height(), &dcMem, 0, 0, SRCCOPY);
	dcMem.SelectObject(pbmOld);
}

void CChildView::OnTimer(UINT_PTR nIDEvent) {
	if (timeId == nIDEvent) {
		// 更新显示时间
		curTime = (curTime + 1) % 1000;
		CRect rc;
		GetClientRect(&rc);
		CClientDC dc(this);
		ShowRightNum(&dc, rc, curTime);
	}
}

void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// 游戏结束
	//if (GAME_OVER) return;

	int y = point.x, x = point.y;
	// 获取当前点击的方格位置
	int row = x / alt.HEIGHTOFF;
	int col = y / alt.WIDTHOFF;
	// 不在合法范围内
	if (!InBound(row, col)) return;
	// 响应点击效果
	// 判断当前位置是否是雷
	if (values[row][col] == 9) {
		// 显示所有雷
		ShowAllThunderuk();
		// 游戏结束
		EnableWindow(false);
		return;
	} 
	// 翻开方格
	revealSquare( row, col, 0);


	CWnd::OnLButtonDown(nFlags, point);
}

void CChildView::OnLButtonUp(UINT nFlags, CPoint point) {
	CWnd::OnLButtonUp(nFlags, point);
}

void CChildView::revealSquare(int row, int col, int level) {
	if (level > 1) return;
	// 判断是否已经被翻开
	if (status[row][col]) return;
	// 判断当前位置是否是雷
	if (values[row][col] == 9) {
		return;
	}

	// 更新翻开后的UI
	CClientDC dc(this);
	ShowCell(&dc, row, col, -1);

	// 判断当前位置是否是数字
	if (values[row][col]) {
		return;
	}
	// 空白
	// 翻开周围方格
	for (int i = 0; i < 4; i++) {
		int newR = row + nposx[i];
		int newC = col + nposy[i];
		// 越界
		if (!InBound(newR, newC)) return;
		revealSquare(newR, newC, level + 1);
	}
}

void CChildView::ShowCell(CDC* pDC, int row, int col, int cell)
{
	// 标记翻开
	status[row][col] = 1;
	CDC dcMem;
	dcMem.CreateCompatibleDC(pDC);
	CBitmap* pbmOld = (CBitmap*)(dcMem.SelectObject(&m_bmCells));
	
	if (cell == -1) cell = values[row][col];

	int pos = v_p[cell];

	pDC->StretchBlt(col * alt.WIDTHOFF, alt.TOP_SHOW_H + row * alt.HEIGHTOFF, alt.WIDTHOFF, alt.HEIGHTOFF, &dcMem,
		0, ((pos) & 0x0F) * alt.HEIGHT, alt.WIDTH, alt.HEIGHT, SRCCOPY);
	dcMem.SelectObject(pbmOld);
}

void CChildView::ShowCells(CDC* pDC)
{
	CDC dcMem;
	int nStatus;

	dcMem.CreateCompatibleDC(pDC);
	CBitmap* pbmOld = (CBitmap*)(dcMem.SelectObject(&m_bmCells));

	for (int j = 0; j < H; j++)
	{
		for (int i = 0; i < W; i++)
		{
			nStatus = status[i][j];
			pDC->StretchBlt(i * alt.WIDTHOFF, alt.TOP_SHOW_H + j * alt.HEIGHTOFF, alt.WIDTHOFF, alt.HEIGHTOFF, &dcMem,
				0, ((nStatus) & 0x0F) * alt.HEIGHT, alt.WIDTH, alt.HEIGHT, SRCCOPY);
		}
	}

	dcMem.SelectObject(pbmOld);
}

void CChildView::DrawLCD(CDC* pDC, int x, int y, int width, int num)
{
	CDC dcMem;
	dcMem.CreateCompatibleDC(pDC);
	CBitmap* pbmOld = (CBitmap*)(dcMem.SelectObject(&m_bmNumber));

	width /= 3;

	char buf[4];
	sprintf_s(buf, "%03d", num);
	int top_gap = alt.TOP_SHOW_H - (y << 1);
	for (int i = 0; i < 3; i++)
	{
		if (buf[i] == '-')
			//pDC->BitBlt(x, y, 13, 23, &dcMem, 0, 0,  SRCCOPY);
			pDC->StretchBlt(x, y, width, top_gap, &dcMem, 0, 0, 13, 23, SRCCOPY);
		else
			//pDC->BitBlt(x, y, 13, 23, &dcMem, 0, (11 - buf[i] + '0') * 23, SRCCOPY);
			pDC->StretchBlt(x, y, width, top_gap, &dcMem, 0, (11 - buf[i] + '0') * 23, 13, 23, SRCCOPY);

		x += width;
	}
	dcMem.SelectObject(pbmOld);
}

void CChildView::ShowLeftNum(CDC* pDC, CRect rc, int num) {
	int left_gap = (rc.Width() / 2 - alt.TOP_THUNDERUK_NUM_W ) / 2;
	int top_gap = 5;
	// 绘制左边的 mark数量
	DrawLCD(pDC, left_gap, top_gap, alt.TOP_THUNDERUK_NUM_W, num);

}

void CChildView::ShowRightNum(CDC* pDC, CRect rc, int num) {
	int	left_gap = (rc.Width() / 2 - alt.TOP_THUNDERUK_NUM_W) / 2 + rc.Width() / 2;
	int top_gap = 5;
	// 绘制右边的 时间
	DrawLCD(pDC, left_gap, top_gap, alt.TOP_THUNDERUK_NUM_W, num);
}

void CChildView::ShowBoard(CDC* pDC) {
	CRect rc;
	GetClientRect(rc);
	ShowLeftNum(pDC, rc, THUNDERUK_NUM);
	ShowRightNum(pDC, rc, curTime);
}
	
// 显示所有格
void CChildView::OnShowAllQuare()
{
	// TODO: 在此添加命令处理程序代码
	CClientDC dc(this);
	
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			int v = values[i][j];
			if (v == 9) continue;
			ShowCell(&dc, i, j, -1);
		}
	}
}

// 显示所有雷
void CChildView::ShowAllThunderuk() {
	CClientDC dc(this);
	for (int i = 0; i < H; i++) {
		for (int j = 0; j < W; j++) {
			int v = values[i][j];
			if (v != 9) continue;
			ShowCell(&dc, i, j, THUNDERUK_POS);
		}
	}
	KillTimer(timeId);
	timeId = -1; 
	
}
// 游戏重新开始
void CChildView::OnRestart()
{
	// TODO: 在此添加命令处理程序代码
	init();

}
